package com.xh.easyretry.strategy.time;

import com.xh.easyretry.annotations.TimeAvoidance;
import com.xh.easyretry.annotations.XHRetry;
import com.xh.easyretry.common.XHRetryContext;
import com.xh.easyretry.common.XHTimeAvoidanceContext;
import org.springframework.stereotype.Component;

import java.util.Objects;

import static com.xh.easyretry.common.XHRetryConstants.*;

@Component
public class GradientTimeAvoidanceStrategy implements TimeAvoidanceStrategy {

    private long initInterval = DEFAULT_EXPONENTIAL_INTERVAL;

    private long initMaxInterval = DEFAULT_EXPONENTIAL_MAX_INTERVAL;

    private double initMultiplier = DEFAULT_EXPONENTIAL_MULTIPLIER;

    public long getInitInterval() {
        return initInterval;
    }

    public void setInitInterval(long initInterval) {
        this.initInterval = initInterval;
    }

    public long getInitMaxInterval() {
        return initMaxInterval;
    }

    public void setInitMaxInterval(long initMaxInterval) {
        this.initMaxInterval = initMaxInterval;
    }

    public double getInitMultiplier() {
        return initMultiplier;
    }

    public void setInitMultiplier(double initMultiplier) {
        this.initMultiplier = initMultiplier;
    }

    @Override
    public String getStrategy() {
        return GRADIENT_DELAY_STRATEGY;
    }

    @Override
    public XHTimeAvoidanceContext start(XHRetryContext retryContext) {
        XHRetry xhRetry = retryContext.getXhRetry();
        TimeAvoidance timeAvoidance = xhRetry.timeAvoidance();
        init(timeAvoidance);
        XHTimeAvoidanceContext timeAvoidanceContext = new XHTimeAvoidanceContext(timeAvoidance, this.initMultiplier,
                this.initInterval, this.initInterval, this.initMaxInterval);
        retryContext.setTimeAvoidanceContext(timeAvoidanceContext);
        return timeAvoidanceContext;
    }

    @Override
    public long calculateDelayTime(XHRetryContext retryContext) {
        XHTimeAvoidanceContext timeAvoidanceContext = retryContext.getTimeAvoidanceContext();
        Long interval = timeAvoidanceContext.getInterval();
        Long maxInterval = timeAvoidanceContext.getMaxInterval();
        if (interval > maxInterval) {
            return maxInterval;
        }
        return (long) (interval * timeAvoidanceContext.getMultiplier());
    }

    private void init(TimeAvoidance timeAvoidance) {
        if (!Objects.equals(timeAvoidance.multiplier(), 1)) {
            this.initMultiplier = timeAvoidance.multiplier();
        }
        if (timeAvoidance.time() > 0L) {
            this.initInterval = timeAvoidance.time();
        }
    }
}
